
#include "hal_nrf.h"

#include "contiki.h"
#include "net/netstack.h"

#include "net/packetbuf.h"
#include "net/rime/rimestats.h"
#include "sys/rtimer.h"
#include "contiki-conf.h"

#define ON  1
#define OFF 0

#if RIMEADDR_SIZE == 4
const rimeaddr_t rimeaddr_null = { { 0, 0 , 0 , 0} };
#endif

static volatile uint8_t onoroff = OFF;

static uint8_t u8TxLen = 0;
static uint8_t __attribute__(( aligned(2) )) u8Nrf24_Txbuf[NRF_RADIO_MAX_PAYLOAD_LEN];
#define CLEAN_TXBUF() (u8TxLen = 0)
#define TXBUF_EMPTY() (u8TxLen == 0)

static uint8_t u8RxPipe = 0;
static uint8_t u8RxLen = 0;
static uint8_t u8Nrf24_Rxbuf[RIMEADDR_CONF_SIZE+NRF_RADIO_MAX_PAYLOAD_LEN];
#define CLEAN_RXBUF() (u8RxLen = 0)
#define RXBUF_EMPTY() (u8RxLen == 0)


static uint8_t locked;
#define GET_LOCK() 		locked++
#define RELEASE_LOCK() 	do{if(locked>0)locked--;}while(0)


static int nrf24_radio_on(void);

void radio_irq(void) 
{  
	switch(hal_nrf_get_clear_irq_flags ())
	{
		case (1<<HAL_NRF_MAX_RT):                 // Max retries reached
			hal_nrf_flush_tx();                     // flush tx fifo, avoid fifo jam
			break;

		case (1<<HAL_NRF_TX_DS):                  // Packet sent
			hal_nrf_set_operation_mode(HAL_NRF_PRX);     // Enter RX mode
			break;

		case (1<<HAL_NRF_RX_DR):                  // Packet received
			while (!hal_nrf_rx_fifo_empty ())
			{
				u8RxPipe = hal_nrf_get_rx_data_source();
				u8RxLen = hal_nrf_get_rx_pload_width(u8RxPipe);
				hal_nrf_get_address(u8RxPipe, u8Nrf24_Rxbuf);
				hal_nrf_read_rx_pload(u8Nrf24_Rxbuf+RIMEADDR_CONF_SIZE);
			}
			break;

		case ((1<<HAL_NRF_RX_DR)|(1<<HAL_NRF_TX_DS)): // Ack payload recieved
			while (!hal_nrf_rx_fifo_empty ())
			{
				u8RxPipe = hal_nrf_get_rx_data_source();
				u8RxLen = hal_nrf_get_rx_pload_width(u8RxPipe)+RIMEADDR_CONF_SIZE;
				hal_nrf_get_address(u8RxPipe, u8Nrf24_Rxbuf);
				hal_nrf_read_rx_pload(u8Nrf24_Rxbuf+RIMEADDR_CONF_SIZE);
			}
			break;

		default:
			break;    
	}
}

uint8_t payload[] = {0x5a,0x3a,0x2a,0x5a};
uint8_t paydress[5] = {0};

static int nrf24_radio_init(void)
{
	hal_nrf_init(radio_irq);


	hal_nrf_close_pipe(HAL_NRF_ALL);  
	hal_nrf_open_pipe(HAL_NRF_PIPE0, true);		//PIPO0 RX/TX
	hal_nrf_open_pipe(HAL_NRF_PIPE1, true);		//PIPO1 for rx boradcast

	hal_nrf_set_crc_mode(HAL_NRF_CRC_16BIT);
	hal_nrf_set_auto_retr(15, 500);				//repeat 15 time, delay 500us

	hal_nrf_set_address_width(RIMEADDR_CONF_SIZE);

	hal_nrf_set_address(HAL_NRF_TX, payload);
	hal_nrf_get_address(HAL_NRF_TX, paydress);
	printf("viry address %02x,%02x,%02x,%02x,%02x\n", paydress[0], paydress[1],paydress[2],paydress[3],paydress[4]);
	
  	hal_nrf_set_address(HAL_NRF_PIPE0, rimeaddr_node_addr.u8);    // note id 
  	hal_nrf_set_address(HAL_NRF_PIPE1, rimeaddr_null.u8);   		// broad cast id 

	hal_nrf_set_operation_mode(HAL_NRF_PRX);     // Enter RX mode

	hal_nrf_set_rf_channel(RF_CHANNEL);            // Operating on static channel 
	hal_nrf_set_power_mode(HAL_NRF_PWR_DOWN);        // Power up device
	
	CLEAN_TXBUF();
	CLEAN_RXBUF();
	locked = 0;
}

/*
payload = dest+src+act payload
src+payload max 32 byte
*/
static int nrf24_radio_prepare(const void *payload, unsigned short payload_len)
{
	if(payload_len > NRF_RADIO_MAX_PAYLOAD_LEN+RIMEADDR_CONF_SIZE)
	{
		printf("brf24: payload length=%d is too long.\r\n", payload_len);
		return RADIO_TX_ERR;
	}
    
	while(!(hal_nrf_tx_fifo_empty() || TXBUF_EMPTY()));

	//write dest address to tx address
	hal_nrf_set_address(HAL_NRF_TX, payload);
	hal_nrf_set_operation_mode(HAL_NRF_PTX);     // Enter RX mode
	memcpy(u8Nrf24_Txbuf, payload+RIMEADDR_CONF_SIZE, payload_len-RIMEADDR_CONF_SIZE);	//Jump dest address
    
	return RADIO_TX_OK;
    
}

static int nrf24_radio_transmit(unsigned short payload_len)
{
	u8TxLen = payload_len-RIMEADDR_CONF_SIZE;

	if(onoroff == OFF)
	{
		nrf24_radio_on();
	}

	GET_LOCK();

	hal_nrf_write_tx_pload(u8Nrf24_Txbuf, u8TxLen);
	hal_nrf_ce_plus();
	
	ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
	ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);

	CLEAN_TXBUF();
	
	RELEASE_LOCK();

	return RADIO_TX_OK;
}

static int nrf24_radio_send(const void *payload, unsigned short payload_len)
{
	if(nrf24_radio_prepare(payload, payload_len) == RADIO_TX_ERR)
	{
		return RADIO_TX_ERR;
	}

	return nrf24_radio_transmit(payload_len);  
}

static int nrf24_radio_read(void *buf, unsigned short bufsize)
{  
	uint8_t u8CopyLen = u8RxLen;
	
	if(bufsize < u8RxLen)
	{
		u8CopyLen = u8RxLen;
	}

	memcpy(buf, u8RxLen, u8CopyLen);

	CLEAN_RXBUF();

	return u8CopyLen;
}

static int nrf24_radio_channel_clear(void)
{
	return (hal_nrf_get_carrier_detect() != 1);
}

static int nrf24_radio_receiving_packet(void)
{
	return 0;
}

static int nrf24_radio_pending_packet(void)
{
	return (!RXBUF_EMPTY());
}

static int nrf24_radio_off(void)
{  
	/* Any transmit or receive packets in progress are aborted.
	* Waiting for end of transmission or reception have to be done.
	*/
	if(locked)
	{
		printf("NRF24: try to off while sending/receiving (lock=%u).\r\n", locked);
		return 0;
	}
	/* off only if there is no transmission or reception of packet. */
	if(onoroff == ON && TXBUF_EMPTY())
	{
		hal_nrf_set_power_mode(HAL_NRF_PWR_DOWN);
		onoroff = OFF;
		ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
	}

	return 1;
}

static int nrf24_radio_on(void)
{
	printf("nrf24: turn radio on\n");
	if(onoroff == OFF)
	{
		hal_nrf_set_power_mode(HAL_NRF_PWR_UP);
		hal_nrf_set_operation_mode(HAL_NRF_PRX);     // Enter RX mode
		onoroff = ON;
		ENERGEST_ON(ENERGEST_TYPE_LISTEN);
	}

	return 1;
}

const struct radio_driver nrf24_radio_driver =
 {
    nrf24_radio_init,
    nrf24_radio_prepare,
    nrf24_radio_transmit,
    nrf24_radio_send,
    nrf24_radio_read,
    nrf24_radio_channel_clear,
    nrf24_radio_receiving_packet,
    nrf24_radio_pending_packet,
    nrf24_radio_on,
    nrf24_radio_off,
  };

